package com.zcsy.commons.upload;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;

/**
 * @Title: FTPUtil.java
 * @Package： com.zcsy.commons.upload 
 * @Description: ftp服务器操作类
 * 说明：在上传连接ftp服务器时，避免频繁的断开再连，会出现文件的乱码
 * @author tanhuatang 786468449@qq.com
 * @Copyright: 2015 武汉中财数元信息技术有限公司 All rights reserved.
 * @date 2016年1月10日
 * @version 1.0
 * @see JDK1.7.0_75
 * @since
 */
public class FTPUtil {

    private static String LOCAL_CHARSET = "GBK";          //本地编码
    private static String FTP_CHARSET   = "iso-8859-1";   //FTP服务器编码
    private static FTPClient ftpClient = new FTPClient();
    
    /**
     * @Description 连接FTP服务器<br>
     * @param url ftp服务器地址
     * @param port ftp服务器端口
     * @param username ftp服务器登录名
     * @param password ftp服务器登录密码
     * @return 成功返回true,失败返回false
     * @throws IOException 异常
     * @author tanhuatang 786468449@qq.com
     * @date 2016年1月13日
     * @see
     */
    public static boolean connect(String url, int port, String username, String password) throws IOException {
        if (!ftpClient.isConnected()) {
            ftpClient.connect(url, port);
            if (FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
                if (ftpClient.login(username, password)) {
                    if (FTPReply.isPositiveCompletion(ftpClient.sendCommand("OPTS UTF8", "ON"))) {
                        LOCAL_CHARSET = "UTF-8";
                    }
                    ftpClient.enterLocalPassiveMode();
                    //设置上传的文件流
                    ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
                    //设置文件编码
                    ftpClient.setControlEncoding(LOCAL_CHARSET);
                    return true;
                }
            }
        } else return true;
        return false;
    }
    
    /**
     * @Description 断开与FTP服务器的连接<br>
     * @throws IOException 异常
     * @author tanhuatang 786468449@qq.com
     * @date 2016年1月13日
     * @see
     */
    public static void disconnect() throws IOException{  
        if (ftpClient.isConnected()) {
            ftpClient.logout();
            ftpClient.disconnect();
        }
    }
    
    /**
     * @Description 递归创建远程FTP服务器目录<br>
     * @param remote 远程绝对路径
     * @param ftpClient FTPClient对象
     * @return 目录是否创建成功
     * @throws IOException 异常
     * @author tanhuatang 786468449@qq.com
     * @date 2016年1月13日
     * @see
     */
    public static Boolean CreateDirecroty(String remote) throws IOException{  
        Boolean success = true;
        if (!"/".equals(remote)) remote += "/";
        String directory = remote.substring(0, remote.lastIndexOf("/") + 1);
        //如果远程目录不存在，则递归创建远程服务器目录
        if (!directory.equalsIgnoreCase("/") && 
            !ftpClient.changeWorkingDirectory(new String(directory.getBytes(LOCAL_CHARSET), FTP_CHARSET))) {
            int start = 0;
            int end = 0;  
            if (directory.startsWith("/")) {  
                start = 1;  
            } else {
                start = 0; 
            }
            end = directory.indexOf("/", start);
            while (true){
                String subDirectory = new String(remote.substring(start, end).getBytes(LOCAL_CHARSET), FTP_CHARSET);  
                if (!ftpClient.changeWorkingDirectory(subDirectory)) {  
                    if (ftpClient.makeDirectory(subDirectory)) {  
                        ftpClient.changeWorkingDirectory(subDirectory);  
                    } else {
                        return false;  
                    }
                }
                start = end + 1;  
                end = directory.indexOf("/",start);  
                //检查所有目录是否创建完毕  
                if (end <= start) {
                    break;  
                }  
            }
        }
        return success;  
    }
    
    /**
     * @Description ftp服务器上传文件方法<br>
     * @param url ftp服务器地址
     * @param port ftp服务器端口
     * @param username ftp服务器登录账号
     * @param password ftp服务器登录密码
     * @param path ftp服务器保存目录
     * @param filename 上传至ftp服务器的文件名
     * @param input 文件输入流
     * @return 成功返回true，否则返回false
     * @author tanhuatang 786468449@qq.com
     * @date 2016年1月10日
     * @see
     */
    public static Boolean uploadFile(String url, int port, String username, String password, 
                                     String path, String filename, InputStream input) {
        boolean success = false;
        try {
            if (connect(url, port, username, password)) {
                if (path.startsWith("/")) {
                    //创建服务器远程目录结构，创建失败直接返回  
                    if (CreateDirecroty(path)) {
                        String fileName = new String(filename.getBytes(LOCAL_CHARSET), FTP_CHARSET);
                        //检查远程是否存在文件  
                        FTPFile[] files = ftpClient.listFiles(filename);
                        if (files.length == 1) {
                            long remoteSize = files[0].getSize();
                            long localSize = input.available();
                            System.out.println("localSize：" + localSize);
                            System.out.println("remoteSize：" + remoteSize);
                            if (remoteSize >= localSize) {
                                return false;
                            }
                            //尝试移动文件内读取指针,实现断点续传  
                            success = breakpointUpload(filename, input, ftpClient, remoteSize);
                        } else {
                            //保存文件
                            success = ftpClient.storeFile(fileName, input);
                            input.close();
                        }
                    }
                }
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return success; 
    }
    
    /**
     * @Description 断点续传方法<br>
     * @param remoteFile 远程FTP服务器文件名
     * @param inputStream 文件输入流
     * @param ftpClient FTPClient对象
     * @param remoteSize FTP服务器已上传字节数
     * @return 成功返回true,失败返回false
     * @throws IOException 
     * @author tanhuatang 786468449@qq.com
     * @date 2016年1月13日
     * @see
     */
    public static Boolean breakpointUpload(String remoteFile, InputStream inputStream, 
                                           FTPClient ftpClient, long remoteSize) throws IOException {
        OutputStream out = ftpClient.appendFileStream(new String(remoteFile.getBytes(LOCAL_CHARSET), FTP_CHARSET));
        byte[] bytes = new byte[1024];
        int c;
        //跳过已上传部分
        inputStream.skip(remoteSize);
        //读取未上传数据
        while ((c = inputStream.read(bytes)) != -1) {
            out.write(bytes, 0, c);
        }
        return true;  
    }
    
    /**
     * 
     * @Description 根据url地址下载文件<br>
     * @param httpUrl url地址
     * @param saveFile 文件保存目录
     * @return 成功返回true，否则返回false
     * @author tanhuatang 786468449@qq.com
     * @date 2016年1月11日
     * @see
     */
    public static InputStream httpDownload(String httpUrl) {  

        URL url = null;
        URLConnection conn = null;
        InputStream inStream = null;
        
        try {
            url = new URL(httpUrl);
        } catch (MalformedURLException e1) {
            e1.printStackTrace();
            return inStream;
        }

        try {
            //打开连接
            conn = url.openConnection();
            //设置连接参数
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent",
                    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            conn.setDoOutput(true);
            conn.setDoInput(true);
            inStream = conn.getInputStream();  
            return inStream;  
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return inStream;
        } catch (IOException ioe) {
            ioe.printStackTrace();
            return inStream;
        }
    }
    
    /**
     * @Description 删除目录下的文件<br>
     * @param url ftp服务器地址
     * @param port ftp服务器端口
     * @param username ftp服务器登录账号
     * @param password ftp服务器登录密码
     * @param path ftp服务器保存目录
     * @param filename 上传至ftp服务器的文件名
     * @return 成功返回true,失败返回false
     * @author tanhuatang 786468449@qq.com
     * @date 2016年1月17日
     * @see
     */
    public static Boolean deleteFile(String url, int port, String username, String password, 
                                     String path, String filename) {
        boolean success = false;
        try {
            if (connect(url, port, username, password)) {
                ftpClient.changeWorkingDirectory(new String(path.getBytes(LOCAL_CHARSET), FTP_CHARSET));
                success = ftpClient.deleteFile(new String(filename.getBytes(LOCAL_CHARSET), FTP_CHARSET));
            }
        } catch(Exception e) {
            e.printStackTrace();
        }
        return success;
    }
    
    /**
     * @Description 删除目录下所有文件及子目录<br>
     * @param url ftp服务器地址
     * @param port ftp服务器端口
     * @param username ftp服务器登录账号
     * @param password ftp服务器登录密码
     * @param directory 目录
     * @return 成功返回true,失败返回false
     * @author tanhuatang 786468449@qq.com
     * @date 2016年1月17日
     * @see
     */
    public static Boolean deleteDirectory(String url, int port, String username, String password, String directory) {
        boolean success = true;
        try {
            if (connect(url, port, username, password)) {
                removeDirectory(directory);
            }
        } catch(Exception e) {
            e.printStackTrace();
            success = false;
        }
        return success;
    }
    
    /**
     * @Description 递归删除目录<br>
     * @param filePath 目录路径
     * @author tanhuatang 786468449@qq.com
     * @date 2016年1月17日
     * @see
     */
    public static void removeDirectory(String filePath) {
        try {
            ftpClient.changeWorkingDirectory(new String(filePath.getBytes(LOCAL_CHARSET), FTP_CHARSET));
            FTPFile[] files = ftpClient.listFiles(new String(filePath.getBytes(LOCAL_CHARSET), FTP_CHARSET));
            for (int i = 0; i < files.length; i ++) {
                if (files[i].isDirectory() && !files[i].getName().startsWith(".")) {
                    removeDirectory(filePath + "/" + files[i].getName());
                    ftpClient.changeToParentDirectory();
                    ftpClient.removeDirectory(new String(files[i].getName().getBytes(LOCAL_CHARSET), FTP_CHARSET));
                }
                if (files[i].isFile()) {
                    ftpClient.deleteFile(new String(files[i].getName().getBytes(LOCAL_CHARSET), FTP_CHARSET));
                }
            }
            //删除最外层目录
            ftpClient.removeDirectory(new String(filePath.getBytes(LOCAL_CHARSET), FTP_CHARSET));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}